﻿#include "MaterialTextureNodeViewModel.h"

#include "MaterialGraph/Pin/MaterialGraphPinModel.h"
#include "MaterialTextureNodeModel.h"

#include "MaterialGraph/MaterialGraphViewModel.h"
#include "MaterialGraph/Pin/MaterialGraphPinViewModel.h"

#include "Framework/Editor.h"
#include "Project/ProjectModel.h"

#include "Asset/AssetSubsystem.h"

void RMaterialTextureNodeViewModel::BindModel(TSharedObjectPtr<RMaterialGraphNodeModel> InModel, TSharedObjectPtr<RMaterialGraphViewModel> InGraph)
{
    Super::BindModel(InModel, InGraph);

    TextureModel=InModel;

    TextureModel->OnIsParameterChanged.Bind([this](){
        
        int64_t Line= TextureModel->IsParameter()?2:1;
        
        //line 0 is the title
        OutputViewModels[0]->SetLineIndex(Line);
        Line++;
        OutputViewModels[1]->SetLineIndex(Line);
        Line++;
        OutputViewModels[2]->SetLineIndex(Line);
        Line++;
        OutputViewModels[3]->SetLineIndex(Line);
        Line++;
        OutputViewModels[4]->SetLineIndex(Line);
        Line++;
        OutputViewModels[5]->SetLineIndex(Line);
        Line+=6;
        //line 7 is the select texture
        //line 8-11 is the display texture
        InputViewModels[0]->SetLineIndex(Line);
        
        OnNodeLineChanged.ExecuteIfBound();
    });
    
    int64_t Line= TextureModel->IsParameter()?2:1;
        
    //line 0 is the title
    OutputViewModels[0]->SetLineIndex(Line);
    Line++;
    OutputViewModels[1]->SetLineIndex(Line);
    Line++;
    OutputViewModels[2]->SetLineIndex(Line);
    Line++;
    OutputViewModels[3]->SetLineIndex(Line);
    Line++;
    OutputViewModels[4]->SetLineIndex(Line);
    Line++;
    OutputViewModels[5]->SetLineIndex(Line);
    Line+=6;
    //line 7 is the select texture
    //line 8-11 is the display texture
    InputViewModels[0]->SetLineIndex(Line);
}

int64_t RMaterialTextureNodeViewModel::GetLineNum() const
{
    //1 title
    //6 output
    //1 select texture
    //4 display texture
    //1 input
    int64_t Content=1+6+1+4+1;
    if(TextureModel->IsParameter())
    {
        //参数节点标题占用两行
        Content++;
    }
    return Content;
    
}

CString RMaterialTextureNodeViewModel::GetInputPinName(int64_t Index) const
{
    switch(Index)
    {
    case 0:
        return U"纹理坐标(UV)";
    default:
        return U"";
    }
}

CString RMaterialTextureNodeViewModel::GetOutputPinName(int64_t Index) const
{
    switch(Index)
    {
    case 0:
        return U"颜色(RGBA)";
    case 1:
        return U"颜色(RGB)";
    case 2:
        return U"红色通道(R)";
    case 3:
        return U"绿色通道(G)";
    case 4:
        return U"蓝色通道(B)";
    case 5:
        return U"透明度通道(A)";
    default:
        return U"";
    }
}

bool RMaterialTextureNodeViewModel::IsParameter() const
{
    return TextureModel->IsParameter();
}

void RMaterialTextureNodeViewModel::ToggleParameter()
{
    auto ChangePropertyOperation=NewObject<RMaterialFunctionOperation>();

    bool OldValue=TextureModel->IsParameter();
    bool NewValue=!OldValue;
    ChangePropertyOperation->Objects.Add(TextureModel); //确保对象不会被销毁
    RMaterialTextureNodeModelWeakPtr WeakTextureModel=TextureModel;
    ChangePropertyOperation->RedoFunction.Bind([WeakTextureModel,NewValue](TSharedObjectPtr<RMaterialGraphModel>){
        WeakTextureModel->SetIsParameter(NewValue);
    });
    ChangePropertyOperation->UndoFunction.Bind([WeakTextureModel,OldValue](TSharedObjectPtr<RMaterialGraphModel>){
        WeakTextureModel->SetIsParameter(OldValue);
    });

    GraphViewModel->RedoOperation(ChangePropertyOperation);
    GraphViewModel->AddOperation(ChangePropertyOperation);
}

CString RMaterialTextureNodeViewModel::GetParameterName() const
{
    return TextureModel->GetParameterName();
}

void RMaterialTextureNodeViewModel::SetParameterName(const CString &InName)
{
    auto ChangePropertyOperation=NewObject<RMaterialChangeObjectPropertyOperation>();
    ChangePropertyOperation->
        SetObjectAndOffset(
            TextureModel
            ,offsetof(RMaterialTextureNodeModel,ParameterName)
        );
    ChangePropertyOperation->OldValue=TextureModel->ParameterName;
    ChangePropertyOperation->NewValue=InName;
    ChangePropertyOperation->bCanCombine=true;

    GraphViewModel->RedoOperation(ChangePropertyOperation);
    GraphViewModel->AddOperation(ChangePropertyOperation);
}

TSharedObjectPtr<RTexture2D> RMaterialTextureNodeViewModel::GetTexture() const
{
    return TextureModel->GetTexture();
}

CString RMaterialTextureNodeViewModel::GetTextureDisplayName() const
{
    if(TextureModel->GetTexture())
    {
        return TextureModel->GetTexture()->GetNodeName();
    }

    return U"未设置";
}

void RMaterialTextureNodeViewModel::SelectTexture(TSharedObjectPtr<RTexture2D> InTexture)
{
    auto NewTexture= InTexture;
    if(!NewTexture.IsValid())
    {
        return;
    }


    auto Operation = NewObject<RMaterialFunctionOperation>();
    RMaterialFunctionOperationWeakPtr WeakOperation = Operation;
    Operation->Objects.Resize(2);
    Operation->Objects[0] = TextureModel->GetTexture();
    Operation->Objects[1] = NewTexture;
    TWeakObjectPtr<RMaterialTextureNodeModel> WeakTextureModel = TextureModel;

    Operation->RedoFunction.Bind([WeakTextureModel, WeakOperation](TSharedObjectPtr<RMaterialGraphModel>)
    {
        WeakTextureModel->SetTexture(WeakOperation->Objects[1]);
    });

    Operation->UndoFunction.Bind([WeakTextureModel, WeakOperation](TSharedObjectPtr<RMaterialGraphModel>)
    {
        WeakTextureModel->SetTexture(WeakOperation->Objects[0]);
    });


    GraphViewModel->RedoOperation(Operation);
    GraphViewModel->AddOperation(Operation);

}
